﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using Djs.Neuronic.Core;

namespace Djs.Neuronic.UI
{
    /// <summary>
    /// Control který vypadá jako Button, má 4 image podle stavu, a může být průhledný
    /// </summary>
    public class HotButton : Control, IFormMoveNotification
    {
        #region Konstrukce
        public HotButton()
        {
            this.Initialize();
        }
        private void Initialize()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer |
                          ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.SupportsTransparentBackColor |
                          ControlStyles.UserMouse | ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.Opaque, false);
            this.BackColor = Color.Transparent;
            this._InteractivityInit();
        }
        #endregion
        #region Property
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("HotButton")]
        [Description("Obrázek v normálním dostupném stavu")]
        public Image ImageNormal { get { return _ImageNormal; } set { _ImageNormal = value; this._RefreshImage(); } }
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("HotButton")]
        [Description("Obrázek ve stavu Disabled")]
        public Image ImageDisabled { get { return _ImageDisabled; } set { _ImageDisabled = value; this._RefreshImage(); } }
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("HotButton")]
        [Description("Obrázek pod myší nebo s focusem")]
        public Image ImageHot { get { return _ImageHot; } set { _ImageHot = value; this._RefreshImage(); } }
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("HotButton")]
        [Description("Obrázek ve stavu stisknuté myši")]
        public Image ImageDown { get { return _ImageDown; } set { _ImageDown = value; this._RefreshImage(); } }
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("HotButton")]
        [Description("Vykreslit button pokud má prvek nad sebou myš nebo kurzor")]
        public bool DrawButtonOnMouse { get { return _DrawButtonOnMouse; } set { _DrawButtonOnMouse = value; this._RefreshImage(); } }
        /// <summary>
        /// Myš byla stisknuta, ale pohybovala formulářem takže bychom měli ignorovat události Click.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool MouseWasMovingForm { get; private set; }
        private Image _ImageNormal;
        private Image _ImageDisabled;
        private Image _ImageHot;
        private Image _ImageDown;
        private bool _DrawButtonOnMouse;
        #endregion
        #region Interaktivita
        private void _InteractivityInit()
        {
            this.GotFocus += new EventHandler(HotButton_GotFocus);
            this.MouseEnter += new EventHandler(HotButton_MouseEnter);
            this.MouseMove += new MouseEventHandler(HotButton_MouseMove);
            this.MouseMove+=new MouseEventHandler(HotButton_MouseMove);
            this.MouseDown += new MouseEventHandler(HotButton_MouseDown);
            this.MouseUp += new MouseEventHandler(HotButton_MouseUp);
            this.MouseLeave += new EventHandler(HotButton_MouseLeave);
            this.LostFocus += new EventHandler(HotButton_LostFocus);
        }
        void HotButton_GotFocus(object sender, EventArgs e)
        {
            this._RefreshImage();
        }
        void HotButton_LostFocus(object sender, EventArgs e)
        {
            this._RefreshImage();
        }
        void HotButton_MouseEnter(object sender, EventArgs e)
        {
            this._OnMouse = true;
            this._RefreshImage();
        }
        void HotButton_MouseMove(object sender, MouseEventArgs e)
        {
            
        }
        void HotButton_MouseDown(object sender, MouseEventArgs e)
        {
            this._IsDown = true;
            this._RefreshImage();   
        }
        void HotButton_MouseUp(object sender, MouseEventArgs e)
        {
            this._IsDown = false;
            this._RefreshImage();
        }
        void HotButton_MouseLeave(object sender, EventArgs e)
        {
            this._OnMouse = false;
            this._RefreshImage();
        }
        void IFormMoveNotification.FormMoveNotification(object sender, FormMoveNotificationArgs args)
        {
            switch (args.State)
            {
                case FormMoveNotificationState.MouseDown:
                    this.MouseWasMovingForm = false;
                    break;
                case FormMoveNotificationState.BeginMove:
                    this.MouseWasMovingForm = true;
                    break;
            }
        }
        #endregion
        #region Kreslení
        protected override void OnPaint(PaintEventArgs e)
        {
            this.PaintButton(e);
        }
        private void PaintButton(PaintEventArgs e)
        {
            Image image = this._Image;
            Rectangle clientRectangle = this.ClientRectangle;
            if (this._DrawButtonOnMouse && (this._OnMouse || this._IsDown || this.Focused))
            {
                this.InvokePaintBackground(e);
            }
            if (image != null)
            {
                Rectangle imageBound = image.Size.AlignTo(clientRectangle, ContentAlignment.MiddleCenter, true);
                e.Graphics.DrawImage(image, imageBound);
            }
            else
            {
                Rectangle buttonBound = new Rectangle(clientRectangle.X, clientRectangle.Y, clientRectangle.Width - 1, clientRectangle.Height - 1);
                using (Pen pen = new Pen(Color.DarkBlue))
                {
                    pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                    e.Graphics.DrawRectangle(pen, buttonBound);
                }
            }
        }
        private void InvokePaintBackground(PaintEventArgs e)
        {
            System.Windows.Forms.VisualStyles.PushButtonState buttonState = this._GetCurrentButtonState();
            ButtonRenderer.DrawButton(e.Graphics, this.ClientRectangle, buttonState);
        }
        private void _RefreshImage()
        {
            _ImageState state = this._GetCurrentState();
            if (state != this._CurrentImageForState)
            {
                Image image = this._GetImageForState(state);
                this._Image = image;
                if (image == null)
                    this._CurrentImageForState = _ImageState.None;
                else
                    this._CurrentImageForState = state;
                this.Refresh();
            }
        }
        private _ImageState _GetCurrentState()
        {
            if (!this.Enabled) return _ImageState.Disabled;
            if (this._IsDown) return _ImageState.Down;
            if (this._OnMouse) return _ImageState.Hot;
            return _ImageState.Normal;
        }
        private System.Windows.Forms.VisualStyles.PushButtonState _GetCurrentButtonState()
        {
            if (!this.Enabled) return System.Windows.Forms.VisualStyles.PushButtonState.Disabled;
            if (this._IsDown) return System.Windows.Forms.VisualStyles.PushButtonState.Pressed;
            if (this._OnMouse) return System.Windows.Forms.VisualStyles.PushButtonState.Hot;
            return System.Windows.Forms.VisualStyles.PushButtonState.Normal;
        }
        private Image _GetImageForState(_ImageState state)
        {
            switch (state)
            {
                case _ImageState.Normal: return this._ImageNormal;
                case _ImageState.Disabled: return _GetFirstImage(this._ImageDisabled, this._ImageNormal);
                case _ImageState.Hot: return _GetFirstImage(this._ImageHot, this._ImageNormal);
                case _ImageState.Down: return _GetFirstImage(this._ImageDown, this._ImageHot, this._ImageNormal);
            }
            return null;
        }
        private static Image _GetFirstImage(params Image[] images)
        {
            foreach (Image image in images)
            {
                if (image != null) return image;
            }
            return null;
        }
        private Image _Image;
        private _ImageState _CurrentImageForState;
        private bool _OnMouse;
        private bool _IsDown;
        private enum _ImageState { None, Normal, Disabled, Hot, Down }
        #endregion
    }
}
